package pv;

/**
 * 吸烟者问题
 * <p>
 * 吸烟需要用到 烟草、纸、胶水 <br />
 * 有三个抽烟者进程和一个供应者进程 <br />
 * 三个抽烟者中，第一个拥有烟草、第二个拥有纸、第三个拥有胶水 <br />
 * 供应者进程无限地提供三种材料，供应者每次将两种材料放桌子上，拥有剩下那种材料的抽烟者卷一根烟并抽掉它，并给供应者进程一个信号告诉完成了，供
 * 应者就会放另外两种材料再桌上，这个过程一直重复（让三个抽烟者轮流地抽烟）
 * </p>
 * <p>
 * 互斥关系：桌子 <br />
 * 同步关系：
 * 供应者需要等桌子上没有材料, 才会放材料；吸烟者要等桌子上有材料, 才能吸烟
 * 三个吸烟者每次吸烟所需的材料不同, 因此要设置三个信号量
 * </p>
 *
 * @author yezh
 * @date 2024/7/4 19:23
 */
public class Smoker {

    private static final Semaphore MUTEX = new Semaphore(1, "MUTEX");
    private static final Semaphore OFFER1 = new Semaphore(0, "OFFER1");
    private static final Semaphore OFFER2 = new Semaphore(0, "OFFER2");
    private static final Semaphore OFFER3 = new Semaphore(0, "OFFER3");
    private static final Semaphore FINISH = new Semaphore(0, "FINISH");

    public static void main(String[] args) {
        new Thread(Smoker::offer).start();
        new SleepLoopThread(Smoker::smoke1, 2).start();
        new SleepLoopThread(Smoker::smoke2, 2).start();
        new SleepLoopThread(Smoker::smoke3, 2).start();
    }

    private static void offer() {
        int i = 0;
        while (true) {
            if (i == 0) {
                MUTEX.p();
                System.out.println("offer1");
                MUTEX.v();
                OFFER1.v();
            } else if (i == 1) {
                MUTEX.p();
                System.out.println("offer2");
                MUTEX.v();
                OFFER2.v();
            } else if (i == 2) {
                MUTEX.p();
                System.out.println("offer3");
                MUTEX.v();
                OFFER3.v();
            }
            i = (i + 1) % 3;
            FINISH.p();
        }
    }

    private static void smoke1() {
        OFFER1.p();
        MUTEX.p();
        System.out.println("smoke1 smoking");
        MUTEX.v();
        FINISH.v();
    }

    private static void smoke2() {
        OFFER2.p();
        MUTEX.p();
        System.out.println("smoke2 smoking");
        MUTEX.v();
        FINISH.v();
    }

    private static void smoke3() {
        OFFER3.p();
        MUTEX.p();
        System.out.println("smoke3 smoking");
        MUTEX.v();
        FINISH.v();
    }

}
